/* $RCSFile: DynEntity.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/CRMWrapper3/DynEntities/DynEntity.cs $
 * $log$
 * Revision 57 2010/10/03 22:26:39  christian.surieux
 *   Added test to avoid create on entities which can't be created
 * Revision 19 2010/10/02 14:49:04  christian.surieux
 *   Updated ADNDynImage for PimaryFieldStringValue, added name override and changed Telerik version
 * Revision 6 2010/08/06 19:56:33  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Diagnostics;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using System.Reflection;

using AddonNice.Settings;

using CrmSdk;

using Cache2    =   AddonNice.Settings.Cache.CurrentCache;


namespace AddonNice.CRMWrapper
{

    #region typecodes enum
    public enum ADNTypeCodes
    {
        NoEntity        = -1,
        unknown         = 0,
        Account         = 1,
        AccountLeads    = 16,
        ActivityMimeAttachment = 1001,
        ActivityParty = 135,
        ActivityPartyRollupByAccount = 4603,
        ActivityPartyRollupByContact = 4604,
        ActivityPointer = 4200,
        Annotation = 5,
        AnnualFiscalCalendar = 2000,
        Appointment = 4201,
        AttributeMap = 4601,
        BulkImport = 4407,
        BulkOperation = 4406,
        BulkOperationLog = 4405,
        BusinessUnit = 10,
        BusinessUnitMap = 6,
        BusinessUnitNewsArticle = 132,
        Calendar = 4003,
        CalendarRule = 4004,
        Campaign = 4400,
        CampaignActivity = 4402,
        CampaignActivityItem = 4404,
        CampaignItem = 4403,
        CampaignResponse = 4401,
        Commitment = 4215,
        Competitor = 123,
        CompetitorAddress = 1004,
        CompetitorProduct = 1006,
        CompetitorSalesLiterature = 26,
        ConstraintBasedGroup = 4007,
        Contact = 2,
        ContactInvoices = 17,
        ContactLeads = 22,
        ContactOrders = 19,
        ContactQuotes = 18,
        Contract = 1010,
        ContractDetail = 1011,
        ContractTemplate = 2011,
        CustomerAddress = 1071,
        CustomerOpportunityRole = 4503,
        CustomerRelationship = 4502,
        Discount = 1013,
        DiscountType = 1080,
        DocumentIndex = 126,
        Email = 4202,
        EntityMap = 4600,
        Equipment = 4000,
        Fax = 4204,
        FilterTemplate = 30,
        FixedMonthlyFiscalCalendar = 2004,
        ImportConfig = 4408,
        Incident = 112,
        IncidentResolution = 4206,
        IntegrationStatus = 3000,
        InternalAddress = 1003,
        Invoice = 1090,
        InvoiceDetail = 1091,
        KbArticle = 127,
        KbArticleComment = 1082,
        KbArticleTemplate = 1016,
        Lead = 4,
        LeadAddress = 1017,
        LeadCompetitors = 24,
        LeadProduct = 27,
        Letter = 4207,
        License = 2027,
        List = 4300,
        ListMember = 4301,
        MonthlyFiscalCalendar = 2003,
        Opportunity = 3,
        OpportunityClose = 4208,
        OpportunityCompetitors = 25,
        OpportunityProduct = 1083,
        OrderClose = 4209,
        Organization = 1019,
        OrganizationMap = 7,
        OrganizationUI = 1021,
        PhoneCall = 4210,
        PluginType = 4602,
        PriceLevel = 1022,
        PrincipalObjectAccess = 11,
        Privilege = 1023,
        PrivilegeObjectTypeCodes = 31,
        Product = 1024,
        ProductAssociation = 1025,
        ProductPriceLevel = 1026,
        ProductSalesLiterature = 21,
        ProductSubstitute = 1028,
        QuarterlyFiscalCalendar = 2002,
        Queue = 2020,
        QueueItem = 2029,
        Quote = 1084,
        QuoteClose = 4211,
        QuoteDetail = 1085,
        RelationshipRole = 4500,
        RelationshipRoleMap = 4501,
        Resource = 4002,
        ResourceGroup = 4005,
        ResourceSpec = 4006,
        Role = 1036,
        RolePrivileges = 12,
        RoleTemplate = 1037,
        RoleTemplatePrivileges = 28,
        SalesLiterature = 1038,
        SalesLiteratureItem = 1070,
        SalesOrder = 1088,
        SalesOrderDetail = 1089,
        SavedQuery = 1039,
        SemiAnnualFiscalCalendar = 2001,
        Service = 4001,
        ServiceAppointment = 4214,
        ServiceContractContacts = 20,
        Site = 4009,
        StatusMap = 1075,
        StringMap = 1043,
        Subject = 129,
        Subscription = 29,
        SystemUser = 8,
        SystemUserLicenses = 13,
        SystemUserPrincipals = 14,
        SystemUserRoles = 15,
        Task = 4212,
        Team = 9,
        TeamMembership = 23,
        Template = 2010,
        Territory = 2013,
        UnresolvedAddress = 2012,
        UoM = 1055,
        UoMSchedule = 1056,
        UserFiscalCalendar = 1086,
        UserQuery = 4230,
        UserSettings = 150,
        WFAction = 1061,
        WFActionLog = 1062,
        WFCondition = 1064,
        WFEventLog = 1065,
        WFEventQueue = 1092,
        WFParameter = 1066,
        WFProcess = 121,
        WFProcessInstance = 122,
        WFRule = 1067,
        WFRuleLog = 1068,
        WFStep = 1069,
        ADN_EXtend = 50000
    };
    #endregion typecodes enum


    public class DicProperties : SortedDictionary<string, InternalProperty>
    {
        public DicProperties()
        {}
    }

    #region Dev version for each module
    
    public class DynDevVersion : IComparable<DynDevVersion>
    {
        public int Major;
        public int Minor;
        public string Comment;

        public int CompareTo(DynDevVersion o)
        {
            if ( Major == o.Major )
                return Minor-o.Minor;
            return Major-o.Major;
        }
        public override string ToString()
        {
            return string.Format("{0}.{1}",Major,Minor);
        }
    }

    #endregion Dev version for each module


    #region Installer Interface and base class
    
    public interface ICrmInstaller
    {
        DynEntity   NewEntity(string schemaName,CRMWrapperBase wrapper);
        bool        InstallInCrmServer(int PortalID,bool isMainPortal,IDictionary stateSaver,CRMWrapperBase wrapper,DynEntity dynEnt,bool publishCustom,bool publishSiteMap,bool publishIsv);
    }

    public class InstallDynEntity : ICrmInstaller
    {
        public virtual DynEntity NewEntity(string schemaName,CRMWrapperBase wrapper)
        {
            return null;
        }

        public virtual bool InstallInCrmServer(int PortalID,bool isMainPortal,IDictionary stateSaver,CRMWrapperBase wrapper,DynEntity dynEnt,bool publishCustom,bool publishSiteMap,bool publishIsv)
        {
            bool ret    =   true;
            if ( dynEnt.HasIFrameBuilder )
                ret     =   dynEnt.InsertIFrame(PortalID, stateSaver,publishCustom,publishSiteMap,publishIsv);
            if ( ret && dynEnt.HasFormCustomizer)
                ret     =   dynEnt.CustomizeForm(stateSaver,publishCustom,publishSiteMap,publishIsv);
            if ( ret && isMainPortal && dynEnt.HasAddonNiceMenuExtension)
                ret     =   dynEnt.CompleteSiteMap(PortalID,stateSaver,publishCustom,publishSiteMap,publishIsv);
            return ret;
        }
    }

    #endregion Installer Interface and base class


    #region EventArg and delegate for DynEntity calls to be used by external classes

    public enum DynEntityEventType: int { Unknown=0,Localize,Created,Retrieved,Update,Delete };


    /// <summary>
    /// Define a custom EventArg class for DynEntity events
    /// </summary>
    public class DynEntityEventArgs : EventArgs
    {
        public DynEntityEventType EvType    =   DynEntityEventType.Unknown;
        public DynEntity Sender             =   null;

	    public DynEntityEventArgs(DynEntity sender,DynEntityEventType tp)
	    {
            Sender                          =   sender;
            EvType                          =   tp;
	    }
    }
	
    public class DynEntityLocalizeArgs : DynEntityEventArgs 
    {
        public string PropertyName      =   string.Empty;
        public int LCID                 =   -1;
        public string Value             =   string.Empty;
        public string LocalizedValue    =   string.Empty;
        public bool Found               =   false;
        public bool GetCrmValue         =   false;

	    public DynEntityLocalizeArgs(DynEntity sender,string wPropertyName,int wLCID): base(sender,DynEntityEventType.Localize)
	    {
            PropertyName                =   wPropertyName;
            LCID                        =   wLCID;
	    }
    }

    /// <summary>
    /// Define a new delegate which uses our custom eventArg class above
    /// </summary>
    public delegate void CrmDynEntityEventHandler(DynEntity sender, DynEntityEventArgs e);
    
    // Allows to define in each DynEntity an Event to get current CRM wrapper value
    public delegate void ResetWrapperHandler(DynEntity dynEnt);

    #endregion EventArg and delegate for DynEntity calls to be used by external classes

    /// <summary>
    /// This class is a wrapper around the Crm DynamicEntity class.
    /// It replaces arrays of attributes by a generic sorted dictionary: SortedDictionary
    /// </summary>
    public class DynEntity : CustomTypeDescriptor
    {
        #region specific properties

        /// <summary>
		/// Version of Entity : should be fixed by developper, it pilots Entity updating, stored in DB
		/// </summary>
		protected DynDevVersion _ADNDynVersion  =   new DynDevVersion(){Major=1, Minor=0,Comment="First Entity Version 01/01/2010"};
		public virtual DynDevVersion ADNDynVersion
		{
			get
			{
                return _ADNDynVersion;
			}
		}

        /// <summary>
        /// To override by correct typecode from the enum ADNTypeCodes
        /// </summary>
        public virtual ADNTypeCodes ADNTypeCode
        {   get{ return ADNTypeCodes.unknown; }}

        DateTime _ADNCreationDate    =   DateTime.UtcNow;

        // Used internally fro cache management in someoccasions
        public DateTime ADNCreationDate
        {
            get
            {
                return _ADNCreationDate;
            }
        }

        #region DicProperty related methods

        DicProperties _dicProperty                          =   new DicProperties();
        
        public DicProperties dicProperty 
        {   get { return _dicProperty;}        }

        /// <summary>
        /// Get access to the list of keys from the sorted dictionary
        /// </summary>
        public DicProperties.KeyCollection Keys
        {   get { return _dicProperty.Keys;}        }

        /// <summary>
        /// Get access to the list of values from the sorted dictionary
        /// </summary>
        public DicProperties.ValueCollection Values
        {   get { return _dicProperty.Values;}        }

        /// <summary>
        /// How many properties exist in the entity
        /// </summary>
        public int Count
        {   get { return _dicProperty.Count;}        }

        public InternalProperty this[string key]
        {
            get
            {
                bool contains   =   dicProperty.ContainsKey(key);
                if (contains)
                    return dicProperty[key];
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity this[{0}] not found", key),CRMDynTraceSwitch.Sw.Info);
                return null;
            }
            set
            {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity this[{0}] set to [{1}]", key, value),CRMDynTraceSwitch.Sw.Info);
                dicProperty[key] = value;

            }
        }

        #endregion DicProperty related methods

        /// <summary>
        /// Has a reset wrapper event been set
        /// </summary>
        public bool IsResetWrapperhandled
        {
            get
            {
                return ( ResetWrapperEvent != null );
            }
        }

        CRMWrapperBase _wrapper             =   null;

        /// <summary>
        /// If a reset wrapper event has been set, call it to be sure we get the last one if we get back from cache
        /// </summary>
        public CRMWrapperBase wrapper
        {
            get
            {
                OnResetWrapperEvent();
                return _wrapper;
            }
        }

        Guid _id                            =   Guid.Empty;
        /// <summary>
        /// Guid Value for the PrimaryKey
        /// </summary>
        public Guid EntityID
        {
            get
            {
                return _id;
            }
            set
            {
                _id                         =   value;
                // install the property with the corresponding key
                SetCrmIdProperty(_id);
            }
        }


        #region Metadata Properties usefull for creation of entity and requesting
        
        /* From Sdk 4.2
        Display Name The name that is displayed to the user. 
        Display Collection Name A plural version of the display name. This only applies to entities. 
        Logical Name The unique name of the class or property created in the Web Services Description Language (WSDL). This name is all lowercase. 
        The logical name is the name that is most widely used when you use the SDK. 
        Note that a custom entity, attribute, or relationship has a prefix in the format described following this table. 
        Schema Name The schema name is specified upon creation. It must be unique. It is used to create the logical name. This name should be in Pascal case. 
        If it is a custom entity, attribute or relationship, it has a prefix in the format described following this table.
        */

        public virtual bool CanCreate
        {
           get
           {
               return true;
           }
        }
        
        /// <summary>
        /// To override in child classes
        /// </summary>
        public virtual bool HasPrimaryField
        {
           get
           {
               return !string.IsNullOrEmpty(PrimaryFieldName);
           }
        }
        
        protected string _PrimaryFieldName =   string.Empty;
        public virtual string PrimaryFieldName
        {
           get
           {
               if ( string.IsNullOrEmpty(_PrimaryFieldName ) )
                    _PrimaryFieldName    =   wrapper.Util.ExtractPrimaryFieldName(EntityMData);
               return _PrimaryFieldName;
           }
           set
           {
               if (value != null)
                   _PrimaryFieldName = value;
           }
        }
       
        /// <summary>
        /// To override in child classes
        /// </summary>
        public virtual bool HasPrimaryKey
        {
           get
           {
               return !string.IsNullOrEmpty(PrimaryKeyName);
           }
        }
        
        protected string _PrimaryKeyName   =   string.Empty;
        public virtual string PrimaryKeyName
        {
           get
           {
               if ( string.IsNullOrEmpty(_PrimaryKeyName) )
                    _PrimaryKeyName =   wrapper.Util.ExtractPrimaryKeyName(EntityMData);
               return _PrimaryKeyName;
           }
           set
           {
               if ( value != null )
                    _PrimaryKeyName  =   value;
           }
        }

        protected string _SchemaName   =   string.Empty;
        public virtual string SchemaName
        {
           get
           {
               if ( string.IsNullOrEmpty(_SchemaName) )
                    _SchemaName =   wrapper.Util.ExtractSchemaName(EntityMData);
               return _SchemaName;
           }
           set
           {
               if ( value != null )
                    _SchemaName  =   value;
           }
        }

        protected string _DisplayName  =   string.Empty;
        public virtual string DisplayName
        {
           get
           {
               if ( string.IsNullOrEmpty(_DisplayName) )
                    _DisplayName =   wrapper.Util.ExtractDisplayName(EntityMData);
               return _DisplayName;
           }
           set
           {
               if ( value != null )
                    _DisplayName  =   value;
           }
        }

        string _DisplayCollectionName    =   string.Empty;
        public string DisplayCollectionName
        {
           get
           {
               if ( string.IsNullOrEmpty(_DisplayCollectionName) )
                    _DisplayCollectionName =   wrapper.Util.ExtractDisplayCollectionName(EntityMData);
               return _DisplayCollectionName;
           }
           set
           {
               if ( value != null )
                    _DisplayCollectionName      =   value;
           }
        }

        string _MetaDataEntityDescription  =   string.Empty;
        public string MetaDataEntityDescription
        {
           get
           {
               if ( string.IsNullOrEmpty(_MetaDataEntityDescription) )
                    _MetaDataEntityDescription    =   wrapper.Util.ExtractDescription(EntityMData);
               return _MetaDataEntityDescription;
           }
           set
           {
               if ( value != null )
                    _MetaDataEntityDescription  =   value;
           }
        }

        protected int _ObjectTypeCode   =   0;
        /// <summary>
        /// The entity typeCode, to override by correct typecode from the enum ADNTypeCodes, cast to int
        /// </summary>
        public virtual int ObjectTypeCode
        {
           get
           {
               if ( _ObjectTypeCode == 0 )
                    _ObjectTypeCode    =   wrapper.Util.ExtractObjectTypeCode(EntityMData);
               return _ObjectTypeCode;
           }
           set
           {
               _ObjectTypeCode          =   value;
           }
        }



        #endregion Metadata Properties usefull for creation of entity and requesting
        
        #endregion specific properties

        #region standard properties often present in crm entities
        
        /// <summary>
        /// Value contained in the PrimaryField for the DynEntity or empty if no PrimaryField
        /// </summary>
        public virtual string PrimaryFieldStringValue
        {
            get
            {
                if ( HasPrimaryField )
                    return StringPropertyValue(PrimaryFieldName);
                return string.Empty;
            }
            set
            {
                if ( HasPrimaryField )
                {
                    AddStringProperty(PrimaryFieldName, value);
                   return;
               }
               const string msg = "[E]DynEntity PrimaryFieldStringValue SET PrimaryFieldName empty.";
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( msg,CRMDynTraceSwitch.Sw.Info);
               throw new ArgumentException(msg);
            }
        }

        /// <summary>
        /// Beware Get method checks if the key is in Properties dictionary, returns Guid.Empty when not present
        /// If PrimaryKeyName is empty returns Guid.Empty
        /// Set only works when PrimaryKeyName is not empty
        /// </summary>
        public virtual Guid PrimaryKeyGuidValue
        {
           get
           {
               if ( HasPrimaryKey &&  dicProperty.ContainsKey(PrimaryKeyName) )
                    return KeyPropertyValue(PrimaryKeyName);
                return Guid.Empty;
           }
           set
           {
               if (HasPrimaryKey)
               {
                   AddKeyProperty(PrimaryKeyName, value);
                   return;
               }
               const string msg = "[E]DynEntity PrimaryKeyGuidValue SET PrimaryKeyName empty.";
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( msg,CRMDynTraceSwitch.Sw.Info);
               throw new ArgumentException(msg);
           }
        }

        /// <summary>
        /// name property if exists, beware, that's not he name of the entity (for this use SchemaName)
        /// </summary>
        [CrmDynAttribute("all")]
        public virtual string name
        {
            get
            {
                return StringPropertyValue(CrmStr.name);
            }
            set
            {
                AddStringProperty(CrmStr.name, value);
            }
        }

        /// <summary>
        /// name property for Addon Nice custom entities
        /// </summary>
        [CrmDynAttribute("all")]
        public virtual string adn_name
        {
            get
            {
                return StringPropertyValue(CrmStr.adnname);
            }
            set
            {
                AddStringProperty(CrmStr.adnname, value);
            }
        }
        /// <summary>
        /// fullname property if exists
        /// </summary>
        [CrmDynAttribute("all")]
        public string fullname
        {
            get
            {
                return StringPropertyValue(CrmStr.fullname);
            }
            set
            {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity SET fullname, SchemaName [{0}], fullname value: [{1}]", SchemaName, value),CRMDynTraceSwitch.Sw.Info);
                AddStringProperty(CrmStr.fullname, value);
            }
        }

        #region import trace

        /// <summary>
        /// Gets or sets the ID of the data import or data migration that created this record. 
        /// </summary>
        [CrmDynAttribute("all")]
        public int importsequencenumber
        {
            get
            {
                if ( ContainsKey(CrmStr.overriddencreatedon) )
                    return NumberPropertyValue(CrmStr.importsequencenumber);
                return -1;
            }
            set
            {
                AddNumberProperty(CrmStr.importsequencenumber,value);
            }
        }

        /// <summary>
        /// Gets or sets the date and time that the record was migrated. 
        /// </summary>
        [CrmDynAttribute("all")]
        public string overriddencreatedon
        {
            get
            {
                if ( ContainsKey(CrmStr.overriddencreatedon) )
                    return DateTimePropertyValue(CrmStr.overriddencreatedon);
                return string.Empty;
            }
        }

        #endregion import trace
    
        /// <summary>
        /// Owner for this object
        /// </summary>
        [CrmDynAttribute("all")]
        public virtual Guid ownerid
        {
            get
            {
                if ( ContainsKey(CrmStr.ownerid) )
                    return OwnerPropertyValue(CrmStr.ownerid);
                return Guid.Empty;
            }
            set
            {
                AddOwnerProperty(CrmStr.ownerid,CrmStr.systemuser,value);
            }
        }

        public string ownerName
        {
            get
            {
                if ( ContainsKey(CrmStr.ownerid) )
                    return OwnerPropertyName(CrmStr.ownerid);
                return string.Empty;
            }
        }

        public string ownerType
        {
            get
            {
                if ( ContainsKey(CrmStr.ownerid) )
                    return OwnerPropertyType(CrmStr.ownerid);
                return string.Empty;
            }
        }

        /// <summary>
        /// Gets the ID of the organization associated with the dynEntity
        /// </summary>
        [CrmDynAttribute("all")]
        public virtual Guid organizationid
        {
            get
            {
                if ( ContainsKey(CrmStr.organizationid) )
                    return LookupPropertyValue(CrmStr.organizationid);
                return Guid.Empty;
            }
        }

        public virtual string organizationName
        {
            get
            {
                if ( ContainsKey(CrmStr.organizationid) )
                    return LookupPropertyName(CrmStr.organizationid);
                return string.Empty;
            }
        }

        /// <summary>
        /// Gets or sets the time zone code in use when the record was created. 
        /// </summary>
        public int utcconversiontimezonecode
        {
            get
            {
                return NumberPropertyValue(CrmStr.utcconversiontimezonecode);
            }
        }

        [CrmDynAttribute("all")]
        public string versionnumber
        {
            get
            { return StringPropertyValue(CrmStr.versionnumber); }
        }
 
        [CrmDynAttribute("all")]
        public string createdon
        {
            get
            {
                return DateTimePropertyValue(CrmStr.createdon);
            }
        }

        public DateTime createdonUTCDate
        {
            get
            {
                return DateTimePropertyDate(CrmStr.createdon,false);
            }
        }

        public DateTime createdonLocalDate
        {
            get
            {
                return DateTimePropertyDate(CrmStr.createdon,true);
            }
        }

        [CrmDynAttribute("all")]
        public Guid createdby
        {
            get
            {
                return LookupPropertyValue(CrmStr.createdby);
            }
        }

        public string createdbyName
        {
            get
            {
                return LookupPropertyName(CrmStr.createdby);
            }
        }

        [CrmDynAttribute(CrmStr.constraintbasedgroup)]
        public string createdbyYomiName
        {
            get
            {
                return LookupPropertyName(CrmStr.createdby);
            }
        }

        [CrmDynAttribute("all")]
        public Guid createdonbehalfby
        {
            get
            {
                return LookupPropertyValue(CrmStr.createdonbehalfby);
            }
        }

        public string createdonbehalfbyName
        {
            get
            {
                return LookupPropertyName(CrmStr.createdonbehalfby);
            }
        }

        [CrmDynAttribute("all")]
        public string modifiedon
        {
            get
            {
                return DateTimePropertyValue(CrmStr.modifiedon);
            }
        }

        public DateTime modifiedonUTCDate
        {
            get
            {
                return DateTimePropertyDate(CrmStr.modifiedon,false);
            }
        }

        public DateTime modifiedonLocalDate
        {
            get
            {
                return DateTimePropertyDate(CrmStr.modifiedon,true);
            }
        }

        [CrmDynAttribute("all")]
        public Guid modifiedby
        {
            get
            {
                return LookupPropertyValue(CrmStr.modifiedby);
            }
        }

        public string modifiedbyName
        {
            get
            {
                return LookupPropertyName(CrmStr.modifiedby);
            }
        }
        
        public string modifiedbyYomiName
        {
            get
            {
                return LookupPropertyName(CrmStr.modifiedby);
            }
        }

        [CrmDynAttribute("all")]
        public Guid modifiedonbehalfby
        {
            get
            {
                return LookupPropertyValue(CrmStr.modifiedonbehalfby);
            }
        }

        public string modifiedonbehalfbyName
        {
            get
            {
                return LookupPropertyName(CrmStr.modifiedonbehalfby);
            }
        }
        
        [CrmDynAttribute("all")]
        public bool workflowsuspended
        {
            get 
            {
                return BooleanPropertyValue(CrmStr.workflowsuspended);
            }
            set 
            {
                AddBooleanProperty(CrmStr.workflowsuspended,value);
            }
        }

        [CrmDynAttribute("all")]
        public int statuscode 
        {
            get 
            {
                return StatusPropertyIntValue(CrmStr.statuscode);
            }
            set 
            {
                AddStatusProperty(CrmStr.statecode,value);// missing name ????
            }
        }

        public string statuscodeName
        {
            get 
            {
                return StatusPropertyNameValue(CrmStr.statuscode);
            }
        }

        [CrmDynAttribute("all")]
        public virtual string statecode
        {
            get 
            {
                return StatePropertyValue(CrmStr.statecode);
            }
            set 
            {
                AddStateProperty(CrmStr.statecode,value);
            }
        }
            
        [CrmDynAttribute("all")]
        public int deletionstatecode
        {
            get
            { return NumberPropertyValue(CrmStr.deletionstatecode); }
            set
            { AddNumberProperty(CrmStr.deletionstatecode,value); }
        }

        #endregion standard properties

        #region CustomTypeDescriptor implementation
        
        #region CustomTypeDescriptor overriden Members

        PropertyDescriptorCollection _propertyDescriptors   =   null;
        EntityInternalMetadata _entityMData = null;

        static public PropertyDescriptorCollection CreatePropertyDescriptorFromAttributes(Type ADNDynType)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapper3 CreatePropertyDescriptorFromAttributes BEG Type: {0}.",
                    ADNDynType),CRMDynTraceSwitch.Sw.Info);
            DynEntity.LocalPropertyDescriptor[] pds =   null;
            SortedList<string,Type> attLst  =   new SortedList<string,Type>();
            // Iterate through all the properties of the class.
            foreach (PropertyInfo pInfo in ADNDynType.GetProperties(BindingFlags.Public))
            {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapper3 CreatePropertyDescriptorFromAttributes Property Name: {0}.",
                        pInfo.Name),CRMDynTraceSwitch.Sw.Info);
                // Iterate through all the Attributes for each method.
                foreach (Attribute attr in Attribute.GetCustomAttributes(pInfo))
                {
                    // Check for the AnimalType attribute.
                    if (attr.GetType() == typeof(CrmDynAttribute))
                    {
                        if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapper3 CreatePropertyDescriptorFromAttributes Property Name: {0}, Entity: {1}, Type: {2}.",
                                pInfo.Name,((CrmDynAttribute)attr).Entity,pInfo.PropertyType),CRMDynTraceSwitch.Sw.Info);
                        attLst.Add(pInfo.Name, pInfo.PropertyType);
                        break;
                    }
                }
            }

            pds                     =   new DynEntity.LocalPropertyDescriptor[attLst.Count];

            // Populate the Property Descriptor collection with Property descriptors
            int count                       =   0;
            foreach (KeyValuePair<string,Type> kv in attLst)
            {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapper3 CreatePropertyDescriptorCollection Attribute  i={0}, Name: {1}, Type: {2}.",
                        count, kv.Key,kv.Value),CRMDynTraceSwitch.Sw.Info);
                pds[count++]                =   new DynEntity.LocalPropertyDescriptor(kv.Key, kv.Value);
            }
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapper3 CreatePropertyDescriptorFromAttributes END Type: {0}, count: {1}.",
                    ADNDynType,count),CRMDynTraceSwitch.Sw.Info);
            return new PropertyDescriptorCollection(pds);
        }
        
        /// <summary>
        /// Used to generate PropertyDescriptors, if not set directly , get it from current wrapper 
        /// this last approach takes all attributes which certainly leads to more attributes than necessary and ineffisciency
        /// </summary>
        public EntityInternalMetadata EntityMData
        {
           get
           {
               if ( _entityMData == null )
                   _entityMData =   wrapper.adminRetrieveEntityMetadata(SchemaName, EntityInternalItems.All);
               return _entityMData;
           }
           set
           {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity EntityMData SET SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
               _entityMData =   value;
           }
        }
        
        public PropertyDescriptorCollection PropertyDescriptorCollection
        {
            get
            {
                if (_propertyDescriptors == null ||
                    ( dicProperty.Count > _propertyDescriptors.Count) )
                {
                    if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity PropertyDescriptorCollection Get BEG SchemaName: {0}, dicProperty.Count: {1}", SchemaName,dicProperty.Count),CRMDynTraceSwitch.Sw.Info);
                    /// if properties already set only attributes present in requested properties for the dynamic entities are created
                   _propertyDescriptors    =    wrapper.CreatePropertyDescriptorCollection(EntityMData,dicProperty,( dicProperty.Count != 0));
                }
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity PropertyDescriptorCollection Get END SchemaName: {0}, dicProperty.Count: {1},_propertyDescriptors.Count: {2}", SchemaName,dicProperty.Count,_propertyDescriptors.Count),CRMDynTraceSwitch.Sw.Info);
                return _propertyDescriptors;
            }
            set
            {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity PropertyDescriptorCollection SET SchemaName: {0}, dicProperty.Count: {1},_propertyDescriptors.Count: {2}", SchemaName,dicProperty.Count,(value == null) ? 0:value.Count),CRMDynTraceSwitch.Sw.Info);
                _propertyDescriptors    =   value;
            }
        }

        public override object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return PropertyDescriptorCollection;
        }

        public override PropertyDescriptorCollection GetProperties()
        {
            return PropertyDescriptorCollection;
        }

        #endregion CustomTypeDescriptor overriden Members

        #endregion CustomTypeDescriptor implementation

        #region LocalPropertyDescriptor Class

        /// <summary>
        /// Mandatory for binding
        /// </summary>
        public class LocalPropertyDescriptor : PropertyDescriptor
        {
            private Type _valueType;
        
            public LocalPropertyDescriptor(string name, Type valueType)
                : base(name, new Attribute[0])
            {
                _valueType  =   valueType;
            }

            public override bool CanResetValue(object component)
            {
                return false;
            }

            public override object GetValue(object component)
            {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity LocalPropertyDescriptor.GetValue BEG ((DynEntity)component)={0} name=[{1}] valuetype:[{2}]", 
                        ((DynEntity)component).SchemaName, Name, _valueType),CRMDynTraceSwitch.Sw.Info);
                object ob                       =   null;
                try
                {
                    if ( ((DynEntity)component).dicProperty.ContainsKey(Name) )
                    {
                        InternalProperty result =   ((DynEntity)component).dicProperty[Name];
                        ob                      =   ((DynEntity)component).wrapper.GetPropertyValue(result);
                    }
                    else if ( _valueType == typeof(string) )
                        ob                      =   string.Empty;
                }
                catch (Exception ex)
                {
                    string msg  =   string.Format("[V]DynEntity LocalPropertyDescriptor.GetValue name=[{0}] valuetype:[{1}] ex: {2}", Name, _valueType, ex);
                    if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( msg,CRMDynTraceSwitch.Sw.Info);
                    throw new CRMWrapperException(msg,ex);
                }
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity LocalPropertyDescriptor.GetValue name: {0}, valuetype: {1}, Value: {2}", Name, _valueType, ob),CRMDynTraceSwitch.Sw.Info);
                return ob;
            }

            public override void ResetValue(object component)
            {
                throw new NotSupportedException();
            }

            public override void SetValue(object component, object value)
            {
                throw new NotSupportedException();
            }

            public override bool ShouldSerializeValue(object component)
            {
                return false;
            }

            public override Type ComponentType
            {
                get
                {
                    return typeof(DynEntity);
                }
            }

            public override bool IsReadOnly
            {
                get
                {
                    return true;
                }
            }

            public override Type PropertyType
            {
                get
                {
                    return _valueType;
                }
            }
        }

        #endregion LocalPropertyDescriptor Class

        #region constructors

        /// <summary>
        /// Some classes have an owninguser and not an owner (Cf salesorderdetail)
        /// </summary>
        public virtual bool HasOwnerProperty
        {
            get{   return true;}
        }

        /// <summary>
        /// Some classes have an owninguser and not an owner (Cf salesorderdetail)
        /// </summary>
        public virtual bool HasOwninguser
        {
            get{   return false;}
        }

        /// <summary>
        /// Some classes have a businessunit  and no owningbusinessunit
        /// </summary>
        public virtual bool HasBusinessUnitProperty
        {
            get{   return false;}
        }

        /// <summary>
        /// Some classes have an owningbusinessunit and no businessunit
        /// </summary>
        public virtual bool HasOwningBusinessUnitProperty
        {
            get{   return false;}
        }

        /// <summary>
        /// Some classes have an owningbusinessunit as an uniqueidentifier
        /// </summary>
        public virtual bool OwningbusinessunitAsUniqueIdentifier
        {
            get{   return false;}
        }

        public static string GetCackeKey(string entName,Guid CrmId,CRMWrapperBase wrapper)
        {
            string result           =   string.Format("{0}_{1}_{2}_{3}",new object[]{entName,CrmId,wrapper.CrmVersion,wrapper.OrganizationName});
            if ( CRMDynCacheTrace.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity GetCackeKey CALLED result: '{0}'.", result),CRMDynCacheTrace.Sw.Info);
            return result;
        }

        public bool isInCache()
        {
            string key              =   GetCackeKey(SchemaName,PrimaryKeyGuidValue,wrapper);
            return Cache2.Exists(key);
        }

        public bool ResetCache(bool InsertIfNotIn)
        {
            string entName  =   SchemaName;
            Guid CrmId      =   PrimaryKeyGuidValue;
            if ( CRMDynCacheTrace.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity ResetCache BEG Entity_Name: {0}, CrmId: {1}", entName,CrmId),CRMDynCacheTrace.Sw.Info);
            string key      =   GetCackeKey(SchemaName,PrimaryKeyGuidValue,wrapper);
            bool cExist     =   Cache2.Exists(key);
            if ( InsertIfNotIn || cExist  )
            {
                Retrieved   =   true;// forced because not set from operations like RetrieveMultiple
                if ( cExist )
                    Cache2.Remove(key);
                Cache2.InsertLong(key,this);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Allow caching for any DynEntity child class
        /// </summary>
        public static T GetFromCache<T>(string entName,CRMWrapperBase wrapper,ResetWrapperHandler fn,Guid CrmId) where T : DynEntity,new()
        {
            return GetFromCache<T>(entName,wrapper,fn,CrmId,true);
        }

        /// <summary>
        /// Allow caching for any DynEntity child class
        /// </summary>
        public static T GetFromCache<T>(string entName,CRMWrapperBase wrapper,ResetWrapperHandler fn,Guid CrmId,bool isAdmin) where T : DynEntity, new()
        {
            // This is not authorized in c# 3 string entName  =   T.DynTypename;
            if ( CRMDynCacheTrace.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity GetFromCache BEG Entity_Name: {0}, CrmId: {1}, time: {2}", entName,CrmId,DateTime.Now),CRMDynCacheTrace.Sw.Info);
            string key              =   GetCackeKey(entName,CrmId,wrapper);
            if ( Cache2.Exists(key) )
            {
                if ( CRMDynCacheTrace.Sw.TraceVerbose )
                    Trace.WriteLine("[V]DynEntity GetFromCache FOUND in cache.",CRMDynCacheTrace.Sw.Info);
                return (T)Cache2.Get(key);
            }
            if ( CRMDynCacheTrace.Sw.TraceVerbose )
                Trace.WriteLine("[V]DynEntity GetFromCache NOT FOUND in cache.",CRMDynCacheTrace.Sw.Info);
            T s                     =   new T();
            s.SchemaName            =   entName;
            s.ResetWrapperEvent     +=  fn;
            s.EntityID              =   CrmId;
            
            bool found              =   (isAdmin ) ? s.adminRetrieve(): s.Retrieve();

            if ( found )
            {
               Cache2.InsertLong(key,s);
            }
            if ( CRMDynCacheTrace.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]DynEntity GetFromCache END inserted in cache: {0}, key: {1}, time: {2}",found,key,DateTime.Now),CRMDynCacheTrace.Sw.Info);
            return s;
        }

        /// <summary>
        /// constructor used for creation
        /// </summary>
        public DynEntity(CRMWrapperBase w, string entity_name)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Create Ctor BEG Entity_Name: {0}.", entity_name),CRMDynTraceSwitch.Sw.Info);
            SchemaName      =   entity_name;
            _wrapper        =   w;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity Ctor END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// constructor used for creation
        /// </summary>
        public DynEntity(ResetWrapperHandler fn, string entity_name)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Create Ctor with ResetWrapper BEG Entity_Name: {0}", entity_name),CRMDynTraceSwitch.Sw.Info);
            SchemaName          =   entity_name;
            ResetWrapperEvent   +=   fn;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity Ctor END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Internally used by constructor to set various properties according to connected user
        /// Beware, by default install wrapper.userid as owner (when wrapper fully iniialized)
        /// </summary>
        public virtual void SetOwnerFromUserId()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity SetOwnerFromUserId BEG SchemaName: {0},HasOwnerProperty: {1},HasBusinessUnitProperty: {2}", SchemaName,HasOwnerProperty,HasBusinessUnitProperty),CRMDynTraceSwitch.Sw.Info);
            // owner, beware, not valid for update
            if (HasOwnerProperty && wrapper.isInitialized )
            {
                ownerid =   wrapper.userId;
            }
        }

        /// <summary>
        /// Constructor used for retrieving
        /// </summary>
        public DynEntity(CRMWrapperBase w, string entity_name, Guid CrmId)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Retrieve Ctor BEG name: {0}, CrmId: {1}", entity_name, CrmId),CRMDynTraceSwitch.Sw.Info);
            SchemaName  =   entity_name;
            _wrapper    =   w;
            _id         =   CrmId;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity Ctor END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Constructor used for retrieving, variant using a resetwrapperhandler allowing to go in cache
        /// </summary>
        public DynEntity(ResetWrapperHandler fn,string entity_name, Guid CrmId)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Retrieve Ctor with ResetWrapper BEG name: {0}, CrmId: {1}", entity_name, CrmId),CRMDynTraceSwitch.Sw.Info);
            SchemaName          =   entity_name;
            ResetWrapperEvent   +=  fn;
            _id                 =   CrmId;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity Ctor END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Constructor used for transforming a real DynamicEntity in DynEntity (when retrieving)
        /// </summary>
        /// <param name="w">wrapper to use</param>
        /// <param name="entityName">This is the entity Name</param>
        /// <param name="wcolumnDescriptors">may be null, should contains columns descriptions</param>
        /// <param name="ColSel">may be null, should contains list of attributes</param>
        public DynEntity(CRMWrapperBase w, InternalDynamicEntity dEntity, PropertyDescriptorCollection wcolumnDescriptors,InternalColumnSet ColSel)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine("[V]DynEntity Ctor from InternalDynamicEntity BEG.",CRMDynTraceSwitch.Sw.Info);
            SchemaName              =   w.GetEntityName(dEntity);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Ctor DynamicEntity SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
            _wrapper                =   w;
            w.FillDicProperties(dEntity,ColSel,dicProperty);
            _propertyDescriptors    =   wcolumnDescriptors;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity Ctor END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Constructor used for transforming a real DynamicEntity in DynEntity (when retrieving)
        /// Faster than previous do to entName not extracted
        /// </summary>
        public DynEntity(CRMWrapperBase w,string entName,InternalDynamicEntity dEntity, PropertyDescriptorCollection wcolumnDescriptors,InternalColumnSet ColSel)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine("[V]DynEntity Ctor from InternalDynamicEntity BEG.",CRMDynTraceSwitch.Sw.Info);
            SchemaName              =   entName;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Ctor DynamicEntity SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
            _wrapper                =   w;
            w.FillDicProperties(dEntity,ColSel,dicProperty);
            _propertyDescriptors    =   wcolumnDescriptors;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity Ctor END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Constructor used for transforming a real DynamicEntity in DynEntity (when retrieving)
        /// Variant with ResetWrapperHandlet
        /// </summary>
        /// <param name="fn">ResetWrapperHandler</param>
        /// <param name="entityName">This is the entity Name</param>
        /// <param name="wcolumnDescriptors">may be null, should contains columns descriptions</param>
        /// <param name="ColSel">may be null, should contains list of attributes</param>
        public DynEntity(ResetWrapperHandler fn,InternalDynamicEntity dEntity, PropertyDescriptorCollection wcolumnDescriptors,InternalColumnSet ColSel)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine("[V]DynEntity Ctor with ResetWrapper from InternalDynamicEntity BEG.",CRMDynTraceSwitch.Sw.Info);
            if ( fn == null )
            {
                const string msg    =   "[E]DynEntity Ctor from InternalDynamicEntity ResetWrapperHandler null.";
                if ( CRMDynTraceSwitch.Sw.TraceError )
                    Trace.WriteLine(msg,CRMDynTraceSwitch.Sw.Info);
                throw new Exception(msg);
            }
            ResetWrapperEvent       +=  fn;
            CRMWrapperBase w        =   wrapper;
            SchemaName              =   w.GetEntityName(dEntity);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Ctor DynamicEntity SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
            w.FillDicProperties(dEntity,ColSel,dicProperty);
            _propertyDescriptors    =   wcolumnDescriptors;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity Ctor END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Constructor used for transforming a real DynamicEntity in DynEntity (when retrieving)
        /// Faster than previous do to entName not extracted
        /// Variant with ResetWrapper event
        /// </summary>
        public DynEntity(ResetWrapperHandler fn,string entName,InternalDynamicEntity dEntity, PropertyDescriptorCollection wcolumnDescriptors,InternalColumnSet ColSel)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine("[V]DynEntity Ctor from InternalDynamicEntity BEG.",CRMDynTraceSwitch.Sw.Info);
            if ( fn == null )
            {
                const string msg    =   "[E]DynEntity Ctor from InternalDynamicEntity ResetWrapperHandler null.";
                if ( CRMDynTraceSwitch.Sw.TraceError )
                    Trace.WriteLine(msg,CRMDynTraceSwitch.Sw.Info);
                throw new Exception(msg);
            }
            ResetWrapperEvent       +=  fn;
            CRMWrapperBase w        =   wrapper;
            SchemaName              =   entName;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Ctor DynamicEntity SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
            w.FillDicProperties(dEntity,ColSel,dicProperty);
            _propertyDescriptors    =   wcolumnDescriptors;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity Ctor END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Empty Ctor to use only with templates <T> where T : DynEntity
        /// </summary>
        public DynEntity()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine("[V]DynEntity Empty Ctor from templates called.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// To use after Empty Ctor with templates where T : DynEntity
        /// </summary>
        public void InitTemplate(CRMWrapperBase w, InternalDynamicEntity dEntity, PropertyDescriptorCollection wcolumnDescriptors,InternalColumnSet ColSel)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine("[V]DynEntity InitTemplate BEG.",CRMDynTraceSwitch.Sw.Info);
            _wrapper    =   w;
            SchemaName  =   w.GetEntityName(dEntity);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity InitTemplate DynamicEntity SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
            w.FillDicProperties(dEntity,ColSel,dicProperty);
            _propertyDescriptors    =   (wcolumnDescriptors != null) ? wcolumnDescriptors: wrapper.CreatePropertyDescriptorCollection(EntityMData,dicProperty,false);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity InitTemplate END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// To use after Empty Ctor with templates where T : DynEntity
        /// Variant with ResetWrapper event
        /// </summary>
        public void InitTemplate(ResetWrapperHandler fn,InternalDynamicEntity dEntity, PropertyDescriptorCollection wcolumnDescriptors,InternalColumnSet ColSel)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine("[V]DynEntity InitTemplate BEG.",CRMDynTraceSwitch.Sw.Info);
            if ( fn == null )
            {
                const string msg    =   "[E]DynEntity InitTemplate from InternalDynamicEntity ResetWrapperHandler null.";
                if ( CRMDynTraceSwitch.Sw.TraceError )
                    Trace.WriteLine(msg,CRMDynTraceSwitch.Sw.Info);
                throw new Exception(msg);
            }
            ResetWrapperEvent       +=  fn;
            CRMWrapperBase w        =   wrapper;
            SchemaName              =   w.GetEntityName(dEntity);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity InitTemplate DynamicEntity SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
            w.FillDicProperties(dEntity,ColSel,dicProperty);
            _propertyDescriptors    =   (wcolumnDescriptors != null) ? wcolumnDescriptors: wrapper.CreatePropertyDescriptorCollection(EntityMData,dicProperty,false);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity InitTemplate END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Create a new Universal Entity from a Dynamic CRM Entity
        /// </summary>
        public static DynEntity CreateFromDynamicEntity(CRMWrapperBase w,ResetWrapperHandler fn,InternalDynamicEntity dEntity,PropertyDescriptorCollection wproperties)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity CreateFromDynamicEntity with ResetWrapper BEG.",CRMDynTraceSwitch.Sw.Info);
            DynEntity dEnt          =   CreateFromDynamicEntity(w,dEntity,wproperties);
            if ( fn != null )
                dEnt.ResetWrapperEvent += fn;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity CreateFromDynamicEntity with ResetWrapper END.",CRMDynTraceSwitch.Sw.Info);
            return dEnt;
        }

        public static DynEntity FindEntityByQuery(CRMWrapperBase Wrapper,string SchemaName,InternalQueryExpression qe,ResetWrapperHandler fn,ref int cnt,bool onlyOne,List<DynEntity> Results )
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity FindEntityByQuery BEG SchemaName: {0}.",SchemaName),CRMDynTraceSwitch.Sw.Info);
            int count                       =   0;
            DynEntity dyn                   =   null;
            if ( DynTypes.ContainsKey(SchemaName) )
            {
                Type t                      =   Wrapper.Util.GetType();
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity FindEntityByQuery found Type : {0}.",t.Name),CRMDynTraceSwitch.Sw.Info);
                MethodInfo mi               =   t.GetMethod("FindEntityByQuery");
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity FindEntityByQuery found Method : {0}.",mi.Name),CRMDynTraceSwitch.Sw.Info);
                MethodInfo miConstructed    =   mi.MakeGenericMethod(DynTypes[SchemaName].DynType);
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity FindEntityByQuery constructed Method : {0}.",miConstructed.Name),CRMDynTraceSwitch.Sw.Info);
                object[] args               =   {SchemaName,qe,fn,count,onlyOne,Results};
                dyn                         =   (DynEntity)miConstructed.Invoke(Wrapper.Util, args);
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity FindEntityByQuery END call dyn == null: {0}, count: {1}.",(dyn == null),count),CRMDynTraceSwitch.Sw.Info);
                cnt                         =   count;
                return dyn;
            }

            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity FindEntityByQuery not foun in DynTypes SchemaName: {0}.",SchemaName),CRMDynTraceSwitch.Sw.Info);
            switch (SchemaName)
            {
                case CrmStr.account:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynAccount>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.contact:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynContact>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.lead:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynLead>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.incident:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynIncident>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.systemuser:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynSystemUser>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.product:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynProduct>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.discount:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynDiscount>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.discounttype:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynDiscountType>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.salesorder:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynSalesOrder>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.salesorderdetail:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynSalesOrderDetail>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.quote:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynQuote>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.quotedetail:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynQuoteDetail>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.invoice:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynInvoice>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.invoicedetail:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynInvoiceDetail>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.pricelevel:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynPricelevel>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.productpricelevel:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynProductPricelevel>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.activitypointer:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynActivityPointer>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.appointment:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynAppointment>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.phonecall:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynPhoneCall>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.email:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynEmail>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.letter:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynLetter>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.opportunity:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynOpportunity>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.customerrelationship:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynCustomerRelationShip>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.contract:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynContract>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.subject:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynSubject>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.kbarticle:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynKbArticle>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.territory:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynTerritory>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.uom:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynUom>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.uomschedule:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynUomSchedule>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.transactioncurrency:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynTransactionCurrency>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.list:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynList>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.listmember:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynListMember>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.annotation:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynAnnotation>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.campaignactivity:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynCampaignActivity>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.campaignresponse:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynCampaignResponse>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.salesliterature:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynSalesLiterature>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.businessunitnewsarticle:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynAnnouncement>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.calendar:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynCalendar>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.queue:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynQueue>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                case CrmStr.queueitem:
                    dyn     =   Wrapper.Util.FindEntityByQuery<ADNDynQueueItem>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
                default:
                    dyn     =   Wrapper.Util.FindEntityByQuery<DynEntity>(SchemaName,qe,fn,ref count,onlyOne,Results);
                    break;
            }
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity FindEntityByQuery END call dyn == null: {0}, count: {1}.",(dyn == null),count),CRMDynTraceSwitch.Sw.Info);
            cnt             =   count;
            return dyn;
        }

        #region DynEntity Factory support

        /* TBD check if the singleton pattern in c# shoudn't be used
public sealed class Singleton
{
    Singleton(){}

    public static Singleton Instance
    {   get{ return Nested.instance;}}
    
    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested(){}
        internal static readonly Singleton instance = new Singleton();
    }
}
*/
        /// <summary>
        /// We try to force the calling of Empty ctors to add type in DynTypes
        /// </summary>
        static DynEntity()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity static Ctor BEG.",CRMDynTraceSwitch.Sw.Info);
            Assembly asm            =   Assembly.GetExecutingAssembly();
            foreach (Type type in asm.GetTypes()) 
            {
              if (type.IsSubclassOf(typeof(DynEntity)) && type.IsClass) 
              {
                Type ntp            =   type.GetNestedType("Ftor",BindingFlags.NonPublic);
                bool isMiddle       =   (ntp == null );
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity static Ctor found Name: {0}, Intermediary class: {1}.",type.Name, isMiddle),CRMDynTraceSwitch.Sw.Info);
                if ( isMiddle ) // no need to instanciate
                    continue;
                ConstructorInfo ci  =   type.GetConstructor(Type.EmptyTypes);
                ci.Invoke(new Object[] { }) ; // just to force static member instanciation
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity static Ctor after invoke Name: {0}.",type.Name),CRMDynTraceSwitch.Sw.Info);
              }
            }
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity static Ctor END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Internal class used to fill a sorted dictionary 'DynTypes' used as a base for a DynEntity Factory
        /// with all necessary methods to instanciate CrmWrapper DynEntity obects based on the requested crm schemaname
        /// </summary>
        protected abstract class DFactor
        {
            string entityName;
            public DFactor(string nm)
            {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DFactor Ctor BEG entityName: {0}, DynType: {1}.",nm,DynType.Name),CRMDynTraceSwitch.Sw.Info);
                entityName      =   nm;
                bool exists     =   DynEntity.DynTypes.ContainsKey(nm);
                if ( !exists )
                        DynEntity.DynTypes.Add(nm,this);
                else    DynEntity.DynTypes[nm]  =   this;
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DFactor Ctor END entityName: {0}, {1}.",nm,(exists) ? "changed":"added"),CRMDynTraceSwitch.Sw.Info);
            }

            public abstract Type DynType
            {   get;}
            public abstract string DynTypename
            {   get;}

            public abstract DynEntity Build();
            public abstract DynEntity Build(CRMWrapperBase w, InternalDynamicEntity dEntity, PropertyDescriptorCollection wproperties);
            public abstract DynEntity Build(CRMWrapperBase w,string PrimaryFieldValue);
            public abstract DynEntity Build(CRMWrapperBase w, Guid PrimaryKeyValue);
        }

        protected static SortedList<string,DFactor> DynTypes =   new SortedList<string,DFactor>();

        #endregion DynEntity Factory support

        /// <summary>
        /// Create a new Universal Entity from a Dynamic CRM Entity
        /// </summary>
        public static DynEntity CreateFromDynamicEntity(CRMWrapperBase w, InternalDynamicEntity dEntity, PropertyDescriptorCollection wproperties)
        {
            string entName          =   w.Util.ExtractSchemaName(dEntity);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CreateFromDynamicEntity BEG entity : {0}.",entName),CRMDynTraceSwitch.Sw.Info);
            if ( DynTypes.ContainsKey(entName) )
            {
                DFactor DynFactor   =   DynTypes[entName];
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CreateFromDynamicEntity found in DynTypes entity : {0}, DynTypename: {1}, Type: {2}.",
                        entName,DynFactor.DynTypename,DynFactor.DynType.Name),CRMDynTraceSwitch.Sw.Info);
                return DynFactor.Build(w, dEntity, wproperties);
            }
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CreateFromDynamicEntity not found in DynTypes, return DynEntity: {0}.",entName),CRMDynTraceSwitch.Sw.Info);
            return new DynEntity(w, dEntity, wproperties, null);
        }

        public static DynEntity CreateEmptyDynamicEntity(CRMWrapperBase w,ResetWrapperHandler fn,string schemaName,bool ForCreate)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CreateEmptyDynamicEntity with ResetWrapper BEG entity : {0}.",schemaName),CRMDynTraceSwitch.Sw.Info);
            DynEntity dEnt              =   CreateEmptyDynamicEntity(w,schemaName);
            if ( fn != null )
                dEnt.ResetWrapperEvent  +=  fn;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CreateEmptyDynamicEntity with ResetWrapper END entity : {0}.",schemaName),CRMDynTraceSwitch.Sw.Info);
            return dEnt;
        }

        public static DynEntity CreateEmptyDynamicEntity(CRMWrapperBase w, string schemaName)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CreateEmptyDynamicEntity BEG  entity : {0}.",schemaName),CRMDynTraceSwitch.Sw.Info);

            if ( DynTypes.ContainsKey(schemaName) )
            {
                DFactor DynFactor   =   DynTypes[schemaName];
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CreateEmptyDynamicEntity found in DynTypes entity : {0}, DynTypename: {1}, Type: {2}.",
                        schemaName,DynFactor.DynTypename,DynFactor.DynType.Name),CRMDynTraceSwitch.Sw.Info);
                return DynFactor.Build(w, string.Empty);
            }
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CreateEmptyDynamicEntity not found in DynTypes return DynEntity for: {0}.",schemaName),CRMDynTraceSwitch.Sw.Info);
            return new DynEntity(w,schemaName);
        }

        public static DynEntity Create2RetrieveDynamicEntity(CRMWrapperBase w,ResetWrapperHandler fn,string schemaName,Guid PrimaryKeyValue)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CreateEmptyDynamicEntity with ResetWrapper BEG entity : {0}.",schemaName),CRMDynTraceSwitch.Sw.Info);
            DynEntity dEnt              =   Create2RetrieveDynamicEntity(w,schemaName,PrimaryKeyValue);
            if ( fn != null )
                dEnt.ResetWrapperEvent  +=  fn;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CreateEmptyDynamicEntity with ResetWrapper END entity : {0}.",schemaName),CRMDynTraceSwitch.Sw.Info);
            return dEnt;
        }

        public static DynEntity Create2RetrieveDynamicEntity(CRMWrapperBase w, string schemaName,Guid PrimaryKeyValue)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Create2RetrieveDynamicEntity BEG entity : {0}.",schemaName),CRMDynTraceSwitch.Sw.Info);
            if ( DynTypes.ContainsKey(schemaName) )
            {
                DFactor DynFactor   =   DynTypes[schemaName];
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Create2RetrieveDynamicEntity found in DynTypes entity : {0}, DynTypename: {1}, Type: {2}.",
                        schemaName,DynFactor.DynTypename,DynFactor.DynType.Name),CRMDynTraceSwitch.Sw.Info);
                return DynFactor.Build(w,PrimaryKeyValue);
            }
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Create2RetrieveDynamicEntity not found in DynTypes return DynEntity for: {0}.",schemaName),CRMDynTraceSwitch.Sw.Info);
            return new DynEntity(w,schemaName,PrimaryKeyValue);
        }

        #endregion constructors
        
        #region Install / Uninstall Implementation

        #region Common config values instanciated for each object
		
		public string DBAllUser		                =   Config.InternallAllUsersRole;
		public string DBAllUser2		            =   Config.InternallAllUsersRole+";";

        public string CRMAdmin                      =   Config.CRMAdminRole;
		public string DBAdmin                       =   Config.InternalAdminRole;
        public string DBAdmin2                      =   Config.InternalAdminRole+";";
        
        #endregion common config values
        
        /// <summary>
        /// Used by install proc : when some entity need to add someting in Crm Menu or AddonNice Menu in Crm
        /// </summary>
        public virtual bool HasAddonNiceMenuExtension
        {
            get{ return false;}
        }

        /// <summary>
        /// Used by install proc 
        /// </summary>
        public virtual bool CompleteSiteMap(int PortalID,IDictionary stateSaver,bool publishCustom,bool publishSiteMap,bool publishIsv)
        {   return true;}

        /// <summary>
        /// Used by install proc : when some entity need to cutomize their Crm Form
        /// </summary>
        public virtual bool HasFormCustomizer
        {
            get{ return false;}
        }

        /// <summary>
        /// Used by install proc : when some entity need to insert an iFrame when installed
        /// </summary>
        public virtual bool HasIFrameBuilder
        {
            get{ return false;}
        }

        /// <summary>
        /// Used by install proc : when some entity need to insert an iFrame when installed, Guid of the module to install
        /// </summary>
        public virtual Guid IFrameGuid
        {
            get{ return Guid.Empty;}
        }
        
        /// <summary>
        /// Used by install proc : when some entity need to be installed in CRM
        /// </summary>
        public virtual bool HasBuilder
        {
            get{ return false;}
        }

        /// <summary>
        /// Used by install proc : When true EntityBuilder, if exists, will work in create mode, else it only 'update' existing entity
        /// Redefine to false to only update entity
        /// </summary>
        public virtual bool shouldCreateEntity
        {
            get{ return true;}
        }

        /// <summary>
        /// Used by install proc : MetaDataBuilder used to create entities in CRM 
        /// If some module need a new entity being in crm, it should reurn an EntityBuilder object ready for build
        /// </summary>
        public virtual List<MetaDataBuilder> Builder
        {
            get{ return null;}
        }

        /// <summary>
        /// Used by install proc when some entity Must be created before this one
        /// </summary>
        public virtual bool DependsFromOtherEntities
        {
            get{ return false;}
        }

        /// <summary>
        /// Used by install proc : Ordered List of entities (schema names) from ,which this entity depends
        /// </summary>
        public virtual SortedList<int,string> DependsFrom
        {
            get{ return null;}
        }

        /// <summary>
        /// Used by install proc : when some entity need to add someting in Crm Menu or AddonNice Menu in Crm
        /// </summary>
        public virtual bool CustomizeForm(IDictionary stateSaver,bool publishCustom,bool publishSiteMap,bool publishIsv)
        {
            return false;
        }

        /// <summary>
        /// Used by install proc : When Entity needs an iframe, it should override this method and do the job
        /// This method will be called in CrmInstall called after install, only for install, not for update
        /// </summary>
        public virtual bool InsertIFrame(int PortalID,IDictionary stateSaver,bool publishCustom,bool publishSiteMap,bool publishIsv)
        {
            return false;
        }

        public virtual bool HasEntities2Uninstall
        {
            get{ return false;}
        }
        
        #endregion Install / Uninstall Implementation

        #region wrapper delegate

		public static event CrmDynEntityEventHandler DynEntityEvent;
        public event ResetWrapperHandler ResetWrapperEvent;

		
        /// <summary>
		/// Call back on main DynEntity events 
		/// </summary>
        public void OnDynEntityEvent(DynEntity s,DynEntityEventArgs e)
		{
            bool handlerDefined     =   ( DynEntityEvent != null );
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity OnDynEntityEvent BEG handlerDefined: {0}.",handlerDefined),CRMDynTraceSwitch.Sw.Info);
			if ( handlerDefined )
				DynEntityEvent(s,e);
		}

        /// <summary>
        /// Called to reset the local wrapper property to a more recent value, in case the object is extracted from cache
        /// </summary>
        public void OnResetWrapperEvent()
        {
            bool handlerDefined     =   ( ResetWrapperEvent != null );
            if ( CRMDynWrapperTrace.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity OnResetWrapperEvent BEG handlerDefined: {0}.",handlerDefined),CRMDynWrapperTrace.Sw.Info);
			if ( handlerDefined )
				ResetWrapperEvent(this);
        }
        
        /// <summary>
        /// Reset the CRMWrapperBase for this DynEntity, returns the old value
        /// </summary>
        public CRMWrapperBase SetWrapper(CRMWrapperBase w)
        {
            if ( CRMDynWrapperTrace.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity SetWrapper BEG old=new: {0}.",(_wrapper == null) ? false:w.Equals(_wrapper)),CRMDynWrapperTrace.Sw.Info);
            CRMWrapperBase oldvalue =   _wrapper;
            _wrapper                =   w;
            return oldvalue;
        }

        /// <summary>
        /// Reset the CRMWrapperBase for this DynEntity, returns the old value
        /// </summary>
        public bool HasWrapper(CRMWrapperBase w)
        {
            bool result             =   (_wrapper == null ) ? false:w.Equals(_wrapper);
            if ( CRMDynWrapperTrace.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity SetWrapper HasWrapper old=new: {0}.",result),CRMDynWrapperTrace.Sw.Info);
            return result;
        }
        
        #endregion wrapper delegate

        #region Field Localizer Properties
        
        bool _UseFieldLocalizer     =   false;
        public bool UseFieldLocalizer
        {
            get
            {
                return _UseFieldLocalizer;
            }
            set
            {
                _UseFieldLocalizer = value;
            }
        }

        /// <summary>
        /// Try to extract a localized string value for sent LCID, if not found, get traditionnal Crm value
        /// 1 or 2 delegate call are done depending on values found 
        /// On first call, the Localized value has to be found
        /// If Crm value exists, a second call is done with CrmValue in value to give the handler opportunity to correct value in LocalizedValue
        /// </summary>
        public string StringPropertyValueEx(string key,int LCID)
        {
            string result               =   string.Empty;
            DynEntityLocalizeArgs e     =   new DynEntityLocalizeArgs(this,key,LCID);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity StringPropertyValueEx BEG key: {0}, LCID: {1}.",key,LCID),CRMDynTraceSwitch.Sw.Info);
            OnDynEntityEvent(this,e);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity StringPropertyValueEx Found: {0}, LocalizedValue: {1}.",e.Found,e.LocalizedValue),CRMDynTraceSwitch.Sw.Info);
            if ( e.Found )
            {
                result                  =   e.LocalizedValue;
                if ( !e.GetCrmValue )
                {
                    if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity StringPropertyValueEx END result: {0}.",result),CRMDynTraceSwitch.Sw.Info);
                    return result;
                }
            }
            bool containsKey            =   ContainsKey(key);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity StringPropertyValueEx ContainsKey: {0}.",containsKey),CRMDynTraceSwitch.Sw.Info);
            if ( containsKey && e.GetCrmValue )
            {
                result                  =   wrapper.StringPropertyValue(key,dicProperty);
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity StringPropertyValueEx PropertyValue: {0}.",result),CRMDynTraceSwitch.Sw.Info);
                // If already found try a second call with crm value inside to decide final value
                if ( e.Found )
                {
                    e.Value             =   result;
                    OnDynEntityEvent(this,e);
                    result              =   e.LocalizedValue;
                    if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity StringPropertyValueEx second call LocalizedValue: {0}.",e.LocalizedValue),CRMDynTraceSwitch.Sw.Info);
                }
            }
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity StringPropertyValueEx END result: {0}.",result),CRMDynTraceSwitch.Sw.Info);
            return result;
        }
        
        #endregion Field Localizer Properties

        #region CRM properties worker methods
        /// <summary>
        /// Helper method to add a string as a StringProperty: creates the property, initializes its key and content, add it tointernal dic.
        /// </summary>
        public StringInternalProperty AddStringProperty(string key, string val)
        {
            return wrapper.AddStringProperty(key,val,dicProperty);
        }

        public CrmBooleanInternalProperty AddBooleanProperty(string key, Boolean val)
        {
            return wrapper.AddBooleanProperty(key,val,dicProperty);
        }

        public CrmDateTimeInternalProperty AddDateTimeProperty(String name, string value)
        {
            return wrapper.AddDateTimeProperty(name,value,dicProperty);
        }
        public CrmDateTimeInternalProperty AddDateTimeProperty(String name,DateTime value,bool isUserTime)
        {
            return wrapper.AddDateTimeProperty(name,value,isUserTime,dicProperty);
        }
        public CrmDecimalInternalProperty AddDecimalProperty(String name, Decimal value)
        {
            return wrapper.AddDecimalProperty(name,value,dicProperty);
        }

        public CrmFloatInternalProperty AddFloatProperty(String name, double value)
        {
            return wrapper.AddFloatProperty(name,value,dicProperty);
        }
        public CrmFloatInternalProperty AddDoubleProperty(String name, double value)
        {
            return wrapper.AddFloatProperty(name,value,dicProperty);
        }
        public CrmFloatInternalProperty AddFloatProperty(String name, Single value)
        {
            return wrapper.AddFloatProperty(name,value,dicProperty);
        }

        public CrmMoneyInternalProperty AddMoneyProperty(String name, Decimal value)
        {
            return wrapper.AddMoneyProperty(name,value,dicProperty);
        }

        public CrmNumberInternalProperty AddNumberProperty(String name, int value)
        {
            return wrapper.AddNumberProperty(name,value,dicProperty);
        }

        public CustomerInternalProperty AddCustomerProperty(string name, string type, Guid value)
        {
            return wrapper.AddCustomerProperty(name,type,value,dicProperty);
        }

        public DynamicEntityArrayInternalProperty AddDynamicEntityArrayProperty(String name, InternalDynamicEntityArray value)
        {
            return wrapper.AddDynamicEntityArrayProperty(name,value,dicProperty);
        }

        public EntityNameReferenceInternalProperty AddEntityNameReferenceProperty(String name, string value)
        {
            return wrapper.AddEntityNameReferenceProperty(name,value,dicProperty);
        }

        public KeyInternalProperty AddKeyProperty(String name, Guid value)
        {
            return wrapper.AddKeyProperty(name,value,dicProperty);
        }

        public LookupInternalProperty AddLookupProperty(String name, String type, Guid value)
        {
            return wrapper.AddLookupProperty(name,type,value,dicProperty);
        }
        
        public CalendarRulesInternalProperty AddCalendarRulesProperty(String name, object value)
        {
            return wrapper.AddCalendarRulesProperty(name,value,dicProperty);
        }

        public OwnerInternalProperty AddOwnerProperty(String name, String type, Guid value)
        {
            return wrapper.AddOwnerProperty(name,type,value,dicProperty);
        }

        public PicklistInternalProperty AddPicklistProperty(String name, int value)
        {
            return wrapper.AddPicklistProperty(name,value,dicProperty);
        }

        public StateInternalProperty AddStateProperty(String name, String value)
        {
            return wrapper.AddStateProperty(name,value,dicProperty);
        }

        public StatusInternalProperty AddStatusProperty(String name, int value)
        {
            return wrapper.AddStatusProperty(name,value,dicProperty);
        }

        public UniqueIdentifierInternalProperty AddUniqueIdentifierProperty(String name, Guid value)
        {
            return wrapper.AddUniqueIdentifierProperty(name,value,dicProperty);
        }

        #endregion CRM properties worker methods

        #region Extracting values

        /// <summary>
        /// Use this method to check presence for a key in properties
        /// </summary>
        public bool ContainsKey(string key)
        {
            return  dicProperty.ContainsKey(key);

        }

        /// <summary>
        /// Beware that when a string value is string.empty, CRM server web services doesn't return the corresponding property
        /// This is a bad conception and to live with this, we must return string.Empy when the value is not found.
        /// This could also mean that the attribut is not present....this could be checked with ContainsKey
        /// </summary>
        public string StringPropertyValue(string key)
        {
            // If localizer running call it with LCID
            if ( ( wrapper.UseFieldLocalizer || UseFieldLocalizer ) && wrapper.ShouldLocalize )
                return StringPropertyValueEx(key,wrapper.RequestUserBaseLCID);
            if ( ContainsKey(key) )
                return wrapper.StringPropertyValue(key,dicProperty);
            return string.Empty;
        }

        public bool IsBooleanPropertyValueNull(string key)
        {
            return wrapper.IsBooleanPropertyValueNull(key,dicProperty);
        }
        public bool BooleanPropertyValue(string key)
        {
            return wrapper.BooleanPropertyValue(key,dicProperty);
        }

        public string DateTimePropertyValue(string key)
        {
            return wrapper.DateTimePropertyValue(key,dicProperty);
        }
        public DateTime DateTimePropertyDate(string key,bool toUserTime)
        {
            return wrapper.DateTimePropertyDate(key,dicProperty,toUserTime);
        }

        /// <summary>
        /// return true when not present in dic
        /// </summary>
        public bool IsDecimalPropertyValueNull(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.IsDecimalPropertyValueNull(key,dicProperty);
            return true;
        }
        /// <summary>
        /// decimal values return a special value (0m) when not present in dic
        /// </summary>
        public decimal DecimalPropertyValue(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.DecimalPropertyValue(key,dicProperty);
            return 0m;
        }

        public bool IsFloatPropertyValueNull(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.IsFloatPropertyValueNull(key,dicProperty);
            return true;
        }
        
        /// <summary>
        /// float values return a special value (0f) when not present in dic
        /// </summary>
        [Obsolete("Use DoubleProperty to avoid loosing precision in crm 4")]
        public float FloatPropertyValue(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.FloatPropertyValue(key,dicProperty);
            return 0f;
        }
        
        /// <summary>
        /// It is a FloatProperty but Crm 3 returns a float and Crm 4 a double
        /// float values return a special value (0f) when not present in dic
        /// </summary>
        public double DoublePropertyValue(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.DoublePropertyValue(key,dicProperty);
            return 0f;
        }

        public bool IsMoneyPropertyValueNull(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.IsMoneyPropertyValueNull(key,dicProperty);
            return true;
        }
        
        /// <summary>
        /// money values return a special value (0m) when not present in dic
        /// </summary>
        public decimal MoneyPropertyValue(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.MoneyPropertyValue(key,dicProperty);
            return 0m;
        }

        public bool IsNumberPropertyValueNull(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.IsNumberPropertyValueNull(key,dicProperty);
            return true;
        }

        /// <summary>
        /// number values return a special value (0) when not present in dic
        /// </summary>
        public int NumberPropertyValue(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.NumberPropertyValue(key,dicProperty);
            return 0;
        }
        public bool IsUniqueIdentifierPropertyValueNull(string key)
        {
            return wrapper.IsUniqueIdentifierPropertyValueNull(key,dicProperty);
        }
        public Guid UniqueIdentifierPropertyValue(string key)
        {
            return wrapper.UniqueIdentifierPropertyValue(key,dicProperty);
        }
        public bool IsPicklistPropertyIntValueNull(string key)
        {
            return wrapper.IsPicklistPropertyIntValueNull(key,dicProperty);
        }
        /// <summary>
        /// picklist values return a special value (-1) when not present in dic
        /// </summary>
        public int PicklistPropertyIntValue(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.PicklistPropertyIntValue(key,dicProperty);
            return -1; // picklist value not defined
        }
        public string PicklistPropertyNameValue(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.PicklistPropertyNameValue(key,dicProperty);
            return string.Empty;
        }
        public string PicklistPropertyLabelValue(string key)
        {
            if (ContainsKey(key))
            {
                int val = PicklistPropertyIntValue(key);
                return wrapper.Util.PickListData(key, SchemaName, val);
            }
            return string.Empty;
        }
        public string EntityNameReferencePropertyValue(string key)
        {
            return wrapper.EntityNameReferencePropertyValue(key,dicProperty);
        }
        public Guid KeyPropertyValue(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.KeyPropertyValue(key,dicProperty);
            return Guid.Empty;
        }

        public bool IsLookupPropertyValueNull(string key)
        {
            return wrapper.IsLookupPropertyValueNull(key,dicProperty);
        }
        /// <summary>
        /// Extract the entityname from the lookup
        /// </summary>
        public string LookupPropertyType(string key)
        {
            return wrapper.LookupPropertyType(key,dicProperty);
        }
        /// <summary>
        /// Extract the name (real record name, not the entity name) from the lookup
        /// </summary>
        public string LookupPropertyName(string key)
        {
            return wrapper.LookupPropertyName(key,dicProperty);
        }
        public Guid LookupPropertyValue(string key)
        {
            return wrapper.LookupPropertyValue(key,dicProperty);
        }
        
        public object CalendarRulesPropertyValue(string key)
        {
            return wrapper.LookupPropertyValue(key,dicProperty);
        }
        public int CalendarRulesPropertyLength(string key,DicProperties dic)
        {
            return wrapper.CalendarRulesPropertyLength(key,dicProperty);
        }
        public object CalendarRulesPropertyAtIndex(string key,DicProperties dic,int idx)
        {
            return wrapper.CalendarRulesPropertyAtIndex(key,dicProperty,idx);
        }
        public Guid CalendarRulesPropertyLookupAtIndex(string key,DicProperties dic,int idx)
        {
            return wrapper.CalendarRulesPropertyLookupAtIndex(key,dicProperty,idx);
        }

        public bool IsOwnerPropertyValueNull(string key)
        {
            return wrapper.IsOwnerPropertyValueNull(key,dicProperty);
        }
        public Guid OwnerPropertyValue(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.OwnerPropertyValue(key,dicProperty);
            return Guid.Empty;
        }
        public string OwnerPropertyName(string key)
        {
            return wrapper.OwnerPropertyName(key,dicProperty);
        }
        public string OwnerPropertyType(string key)
        {
            return wrapper.OwnerPropertyType(key,dicProperty);
        }
        public bool IsCustomerPropertyValueNull(string key)
        {
            return wrapper.IsCustomerPropertyValueNull(key,dicProperty);
        }
        public Guid CustomerPropertyValue(string key)
        {
            return wrapper.CustomerPropertyValue(key,dicProperty);
        }
        public string CustomerPropertyName(string key)
        {
            return wrapper.CustomerPropertyName(key,dicProperty);
        }
        public string CustomerPropertyType(string key)
        {
            return wrapper.CustomerPropertyType(key,dicProperty);
        }

        public InternalDynamicEntityArray DynamicEntityArrayProperty(string key)
        {
            if ( ContainsKey(key) )
                return wrapper.DynamicEntityArrayProperty(key,dicProperty);
            return null;
        }

        public string StatePropertyValue(string key)
        {
            return wrapper.StatePropertyValue(key,dicProperty);
        }

        public string IncidentStatePropertyValue(string key)
        {
            return wrapper.IncidentStatePropertyValue(key,dicProperty);
        }

        public string StatePropertyNameValue(string key)
        {
            return wrapper.StatePropertyNameValue(key,dicProperty);
        }
        public int StatusPropertyIntValue(string key)
        {
            return wrapper.StatusPropertyIntValue(key,dicProperty);
        }
        public string StatusPropertyNameValue(string key)
        {
            return wrapper.StatusPropertyNameValue(key,dicProperty);
        }

        #endregion Extracting values

        #region Create Dynamically

        protected virtual void SetCrmIdProperty(Guid crmId)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity SetCrmIdProperty NOT Defined using PrimaryKeyName: {0}.",PrimaryKeyName),CRMDynTraceSwitch.Sw.Info);
            if ( !dicProperty.ContainsKey(PrimaryKeyName) || KeyPropertyValue(PrimaryKeyName) != crmId )
                AddKeyProperty(PrimaryKeyName,crmId);
        }
        
        
        /// <summary>
        /// Create a dynamic entity using current user account
        /// Set the returned Guid in EntityID, calling SetCrmIdProperty to add the real primaryKey property
        /// </summary>
        public virtual Guid Create()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Create SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
            return internalCreate(false);
        }


        /// <summary>
        /// Create a dynamic entity with the admin account
        /// Set the returned Guid in EntityID, calling SetCrmIdProperty to add the real primaryKey property
        /// </summary>
        public virtual Guid adminCreate()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity adminCreate SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
            return internalCreate(true);
        }

        protected virtual Guid internalCreate(bool isAdmin)
        {
            return wrapper.CreateFromDynEntity(this,isAdmin);
        }

        #endregion

        #region Update Dynamically

        /// <summary>
        /// Copy a dynamic entity from a similar value
        /// </summary>
        public bool CopyTo(DynEntity dest,bool doUpdate,ref bool ownerChanged)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CopyTo BEG SchemaName: {0}, dest.SchemaName: {1}, doUpdate: {2}", SchemaName,dest.SchemaName,doUpdate),CRMDynTraceSwitch.Sw.Info);
            if ( SchemaName != dest.SchemaName )
                return false;
            bool HighChange     =   false;
            bool ownChanged     =   false;
            wrapper.Util.ExecForEachDynamicEntityProperty(this,
                delegate(string Nm, object Vl, object val2, object val3, AttributeInternalType tp)
                {
                    switch (tp)
                    {
                        case AttributeInternalType.Float:
                            if ( Vl is double )
                                  dest.AddFloatProperty(Nm,(double)Vl); // v4
                            else  dest.AddFloatProperty(Nm, (float)Vl); // v3
                            break;
                        case AttributeInternalType.Picklist:
                            dest.AddPicklistProperty(Nm, (int)Vl);
                            break;
                        case AttributeInternalType.String:
                            dest.AddStringProperty(Nm, (string)Vl);
                            break;
                        case AttributeInternalType.DateTime:
                            dest.AddDateTimeProperty(Nm, (string)Vl);
                            break;
                        case AttributeInternalType.Boolean:
                            dest.AddBooleanProperty(Nm, (bool)Vl);
                            break;
                        case AttributeInternalType.Memo:
                            dest.AddStringProperty(Nm,(string)Vl);
                        break;
                        case AttributeInternalType.Money:
                            dest.AddMoneyProperty(Nm,(decimal)Vl);
                        break;
                        case AttributeInternalType.Lookup:
                        if (dest.ContainsKey(Nm) && ( dest.LookupPropertyValue(Nm) != (Guid)Vl ) )
                            HighChange  =  true;
                            break;
                        case AttributeInternalType.Customer:
                        if (dest.ContainsKey(Nm) && ( dest.CustomerPropertyValue(Nm) != (Guid)Vl ) )
                            HighChange      =  true;
                            break;
                        case AttributeInternalType.UniqueIdentifier:
                        if (dest.ContainsKey(Nm) && ( dest.UniqueIdentifierPropertyValue(Nm) != (Guid)Vl ) )
                            HighChange      =  true;
                            break;
                        case AttributeInternalType.Owner:
                        if (dest.ContainsKey(Nm) && ( dest.OwnerPropertyValue(Nm) != (Guid)Vl ) )
                            ownChanged      =  true;
                            break;
                        case AttributeInternalType.Status:
                        case AttributeInternalType.CalendarRules:
                        case AttributeInternalType.PartyList:
                        default:
                            break;
                    }
                    return true;
                });
            if ( doUpdate )
                dest.internalUpdate(false);
            ownerChanged                    =   ownChanged;
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]DynEntity CopyTo END HighChange: {0}, ownerChanged: {1}.",HighChange,ownerChanged),CRMDynTraceSwitch.Sw.Info);
            return HighChange;
        }

        public void FastCopyTo(DynEntity dest,bool doUpdate)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity FastCopyTo BEG SchemaName: {0}, dest.SchemaName: {1}, doUpdate: {2}", SchemaName,dest.SchemaName,doUpdate),CRMDynTraceSwitch.Sw.Info);
            if ( SchemaName != dest.SchemaName )
                return;
            foreach ( string key in dicProperty.Keys )
            {
                dest[key] = dicProperty[key];
            }
            if ( doUpdate )
                dest.internalUpdate(false);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]DynEntity FastCopyTo END.",CRMDynTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Update a dynamic entity using current user account
        /// </summary>
        public void Update()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Update BEG SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
            internalUpdate(false);
        }

        /// <summary>
        /// Update a dynamic entity with the admin account
        /// </summary>
        public void adminUpdate()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity adminUpdate SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
            internalUpdate(true);
        }

        protected virtual void internalUpdate(bool isAdmin)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity internalUpdate BEG SchemaName: {0}, isAdmin: {1}",SchemaName,isAdmin),CRMDynTraceSwitch.Sw.Info);
            wrapper.UpdateFromDynEntity(this,isAdmin);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity internalUpdate END updated SchemaName: {0}", SchemaName),CRMDynTraceSwitch.Sw.Info);
        }
        #endregion Update dynamically

        #region Delete Dynamically

        /// <summary>
        /// Delete a dynamic entity using current user account
        /// </summary>
        public void Delete()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Delete BEG SchemaName: {0}",SchemaName),CRMDynTraceSwitch.Sw.Info);
            internalDelete(false);
        }

        /// <summary>
        /// Update a dynamic entity with the admin account
        /// </summary>
        public void adminDelete()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity adminDelete END SchemaName: {0}",SchemaName),CRMDynTraceSwitch.Sw.Info);
            internalDelete(true);
        }

        protected virtual void internalDelete(bool isAdmin)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity internalDelete BEG SchemaName: {0}, isAdmin: {1}",SchemaName,isAdmin),CRMDynTraceSwitch.Sw.Info);
            wrapper.DeleteFromDynEntity(this,isAdmin);
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity internalDelete END deleted SchemaName: {0}",SchemaName),CRMDynTraceSwitch.Sw.Info);
        }
        #endregion Delete dynamically

        #region Retrieve Dynamically
        public bool Retrieved   =   false;
        /// <summary>
        /// Retrieve dynamically with the EntityID set on constructor
        /// </summary>
        public bool Retrieve()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Retrieve BEG SchemaName: {0}, EntityID: {1}",SchemaName, EntityID),CRMDynTraceSwitch.Sw.Info);
            return internalRetrieve(false);
        }

        /// <summary>
        /// Retrieve dynamically with admin account the EntityID set on constructor
        /// </summary>
        public bool adminRetrieve()
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity adminRetrieve BEG SchemaName: {0}, EntityID: {1}",SchemaName, EntityID),CRMDynTraceSwitch.Sw.Info);
            return internalRetrieve(true);
        }

        /// <summary>
        /// Retrieve dynamically with the EntityID set on constructor
        /// Version with a reduced column set to be faster
        /// </summary>
        public bool Retrieve(InternalColumnSet cols)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Retrieve BEG SchemaName: {0}, EntityID: {1}, cols.Lenght: {2}",
                    SchemaName, EntityID,(cols == null ) ? 0:cols.Attributes.Length),CRMDynTraceSwitch.Sw.Info);
            return internalRetrieve(cols,false);
        }

        /// <summary>
        /// Retrieve dynamically with admin account the EntityID set on constructor
        /// Version with a reduced column set to be faster
        /// </summary>
        public bool adminRetrieve(InternalColumnSet cols)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity adminRetrieve BEG SchemaName: {0}, EntityID: {1}, cols.Lenght: {2}",
                    SchemaName, EntityID,(cols == null ) ? 0:cols.Attributes.Length),CRMDynTraceSwitch.Sw.Info);
            return internalRetrieve(cols,true);
        }

        protected virtual bool internalRetrieve(bool isAdmin)
        {
            Retrieved   =   wrapper.RetrieveFromDynEntity(this,isAdmin);
            return Retrieved;
        }

        protected virtual bool internalRetrieve(InternalColumnSet cols,bool isAdmin)
        {
            Retrieved   =   wrapper.RetrieveFromDynEntity(this,cols,isAdmin);
            return Retrieved;
        }
        
        #endregion

        #region assign dynamically

        /// <summary>
        /// Change the owner of current Entity using a Guid
        /// </summary>
        public void Assign(Guid userId)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity Assign BEG SchemaName: {0}, userId: {1}",SchemaName, userId),CRMDynTraceSwitch.Sw.Info);
            internalAssign(userId, false);
        }

        /// <summary>
        /// Change the owner of current EntityAddress using admin account, version using a Guid
        /// </summary>
        public void adminAssign(Guid userId)
        {
            if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity adminAssign BEG SchemaName: {0}, userId: {1}",SchemaName, userId),CRMDynTraceSwitch.Sw.Info);
            internalAssign(userId, true);
        }

        protected virtual void internalAssign(Guid userId, bool isAdmin)
        {
            wrapper.AssignFromDynEntity(this,userId,isAdmin);
        }

        #endregion assigndynamically

        #region Utilities to decode Properties
        /// <summary>
        /// Name contains the lookup attribute name
        /// val3 contains the name from the lookup used for display in forms
        /// Val is the Guid for the lookup
        /// Returns the found lookup DynEntity
        /// </summary>
        public static DynEntity RetrieveLookup(CRMWrapperBase Wrapper,string SchemaName,EntityConfig TConfig,string Name,Guid Val,object val3)
        {
            if (CRMDynTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveLookup BEG Entity: {0}, Lookup Name: {1}",SchemaName,Name),CRMDynTraceSwitch.Sw.Info);
            // type is infortunately always empty for lookup we must ask for metadatadefinition to get the associated entity
            List<string> entLst     =   TConfig.FindPotentialLookupEntities(Name);
            //first loop for accounts/contacts/systemuser
            foreach(string otp in entLst)
            {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                   Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveLookup trying entity: '{0}'",otp),CRMDynTraceSwitch.Sw.Info);
                string strVal2                  =   string.Empty;
                switch(otp)
                {
                    case CrmStr.account:
                        ADNDynAccount waccount  =   new ADNDynAccount(Wrapper,(string)val3);
                        waccount.EntityID      =   Val;
                        if ( !waccount.adminRetrieve() )
                            break;
                        if ( waccount != null )
                        {
                            if (CRMDynTraceSwitch.Sw.TraceVerbose)
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveLookup found account: {0}-{1}",
                                    waccount.name,waccount.accountid),CRMDynTraceSwitch.Sw.Info);
                            return waccount;
                        }
                        break;
                    case CrmStr.contact:
                        ADNDynContact wcontact  =   new ADNDynContact(Wrapper,string.Empty,string.Empty);
                        wcontact.EntityID      =   Val;
                        if ( !wcontact.adminRetrieve() )
                            break;
                        if ( wcontact != null )
                        {
                            if (CRMDynTraceSwitch.Sw.TraceVerbose || CRMDynTraceSwitch.Sw.TraceVerbose)
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveLookup found contact: {0}-{1}",
                                    wcontact.lastname,wcontact.contactid),CRMDynTraceSwitch.Sw.Info);
                            return wcontact;
                        }
                        break;
                    case CrmStr.lead:
                        ADNDynLead  wlead       =   new ADNDynLead(Wrapper,string.Empty,string.Empty);
                        wlead.EntityID         =   Val;
                        if ( !wlead.adminRetrieve() )
                            break;
                        if ( wlead != null )
                        {
                            if (CRMDynTraceSwitch.Sw.TraceVerbose || CRMDynTraceSwitch.Sw.TraceVerbose)
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveLookup found lead: {0}-{1}",
                                    wlead.lastname,wlead.leadid),CRMDynTraceSwitch.Sw.Info);
                            return wlead;
                        }
                        break;
                    case CrmStr.systemuser:
                        ADNDynSystemUser sysuser    =   new ADNDynSystemUser(Wrapper, (string)val3);
                        sysuser.EntityID           =   Val;
                        if ( !sysuser.adminRetrieve() )
                            break;
                        if ( sysuser != null )
                        {
                            if (CRMDynTraceSwitch.Sw.TraceVerbose || CRMDynTraceSwitch.Sw.TraceVerbose)
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveLookup found systemuser: {0}, Val: {1}",sysuser.fullname,Val),CRMDynTraceSwitch.Sw.Info);
                            return sysuser;
                        }
                        break;
                }
            }

            // not in account/contact/lead/systemuser we search for others entities
            foreach(string otp in entLst)
            {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                   Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveLookup trying entity : '{0}'",otp),CRMDynTraceSwitch.Sw.Info);
            
                string strVal2                  =   string.Empty;

                switch(otp)
                {
                    case CrmStr.lead:
                    case CrmStr.account:
                    case CrmStr.contact:
                    case CrmStr.systemuser:
                        break;
                    default:
                        DynEntity newDyn        =   DynEntity.Create2RetrieveDynamicEntity(Wrapper, otp, Val);
                        if (!newDyn.adminRetrieve())
                            break;
                        if (newDyn != null)
                        {
                            if (CRMDynTraceSwitch.Sw.TraceVerbose || CRMDynTraceSwitch.Sw.TraceVerbose)
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveLookup found entity: '{0}'-'{1}'",
                                    newDyn.PrimaryFieldStringValue, newDyn.PrimaryKeyGuidValue), CRMDynTraceSwitch.Sw.Info);
                            return newDyn;
                        }
                        break;
                }
            }
            return null;
        }

        public static DynEntity RetrieveCustomer(CRMWrapperBase Wrapper,string SchemaName,string Name,Guid Val,string otp,object val3)
        {
            if (CRMDynTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveCustomer Entity: {0}, Customer Name: {1}, Customer entity: {2}",SchemaName,Name,otp),CRMDynTraceSwitch.Sw.Info);
            
            string strVal2          =   string.Empty;
            switch(otp)
            {
                case CrmStr.account:
                    ADNDynAccount waccount  =   new ADNDynAccount(Wrapper,(string)val3);
                    waccount.EntityID      =   Val;
                    waccount.adminRetrieve();
                    if ( waccount != null )
                    {
                        if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveCustomer found account: {0}-{1}",
                                waccount.name,waccount.accountid),CRMDynTraceSwitch.Sw.Info);
                        return waccount;
                    }
                    break;
                case CrmStr.contact:
                    ADNDynContact wcontact   =   new ADNDynContact(Wrapper,string.Empty,string.Empty);
                    wcontact.EntityID      =   Val;
                    wcontact.adminRetrieve();
                    if ( wcontact != null )
                    {
                        if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveCustomer found contact: {0}-{1}",
                                wcontact.lastname,wcontact.contactid),CRMDynTraceSwitch.Sw.Info);
                        return wcontact;
                    }
                    break;

                case CrmStr.lead:
                    ADNDynLead wlead         =   new ADNDynLead(Wrapper,string.Empty,string.Empty);
                    wlead.EntityID         =   Val;
                    wlead.adminRetrieve();
                    if ( wlead != null )
                    {
                        if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveCustomer found lead: {0}-{1}",
                                wlead.lastname,wlead.leadid),CRMDynTraceSwitch.Sw.Info);
                        return wlead;
                    }
                    break;

                default:
                    if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveCustomer entity: '{0}', trying name: {1}",otp,Name),CRMDynTraceSwitch.Sw.Info);
                    DynEntity newDyn         =   new DynEntity(Wrapper,otp,Val);
                    if ( newDyn.adminRetrieve() )
                    {
                        if (CRMDynTraceSwitch.Sw.TraceVerbose)
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity RetrieveCustomer found entity: '{0}'-'{1}'",
                                newDyn.PrimaryFieldStringValue, newDyn.EntityID), CRMDynTraceSwitch.Sw.Info);
                        return newDyn;
                    }
                    break;
            }
            return null;
        }

        public static ADNDynSystemUser FindOwner(CRMWrapperBase Wrapper,Guid Val,string flName)
        {
            ADNDynSystemUser sysuser     =   new ADNDynSystemUser(Wrapper,flName);
            sysuser.EntityID            =   Val;
            if ( sysuser.adminRetrieve() )
            {
                if ( CRMDynTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity FindOwner found systemuser: {0}",sysuser.fullname),CRMDynTraceSwitch.Sw.Info);
                return sysuser;
            }
            return null;
        }

        public static DynEntity FindUniqueIdentifier(CRMWrapperBase Wrapper,string propertyname,string SchemaName,Guid Val)
        {
            if (CRMDynTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]DynEntity FindUniqueIdentifier BEG propertyname: {0}, SchemaName: {1}, Val: {2}",
                    propertyname,SchemaName,Val), CRMDynTraceSwitch.Sw.Info);
            DynEntity orgEnt    =   new DynEntity(Wrapper,SchemaName,Val);
            if ( !orgEnt.adminRetrieve() )
                return null;
            return orgEnt;
        }
        
        #endregion Utilities to decode Properties

        #region Serialize into XML and return the string
        public string Serialize()
        {
            return wrapper.Serialize(this);
        }
        #endregion

        #region Deserialize the CRM contact from XML

        public static T Deserialize<T>(CRMWrapperBase w,ResetWrapperHandler fn,string xml)   where T : DynEntity, new()
        {
            return w.Deserialize<T>(fn,xml);
        }
        
        #endregion
        
        #region InitializeFrom

        public DynEntity ConvertTo(string targetEntity,ResetWrapperHandler fn,bool isAdmin)
        {
            Guid createdId  =   wrapper.InitializeFrom(this,targetEntity,isAdmin);
            DynEntity dyn   =   Create2RetrieveDynamicEntity(wrapper,fn,targetEntity,createdId);
            if ( isAdmin )
                 dyn.adminRetrieve();
            else dyn.Retrieve();
            return dyn;
        }

        #endregion InitializeFrom

        #region Utilities for PickLists
        
        public SortedList<int,string> SortedIntListFromPickList(string attName)
        {
            return wrapper.Util.SortedIntListFromPickList(attName,SchemaName);
        }
        
        public SortedList<string,int> SortedStringListFromPickList(string attName)
        {
            return wrapper.Util.SortedStringListFromPickList(attName,SchemaName);
        }
        
        
        public string PickListValueFromInt(string attName,int val)
        {
            SortedList<int,string> lst  =   SortedIntListFromPickList(attName);
            if ( lst.ContainsKey(val) )
                return lst[val];
            return string.Empty;
        }
        
        public int PickListValueFromString(string attName,string val)
        {
            SortedList<string,int> lst  =   wrapper.Util.SortedStringListFromPickList(attName,SchemaName);
            if ( lst.ContainsKey(val) )
                return lst[val];
            return 0;
        }

        #endregion Utilities for PickLists
    }
}
